

#ifndef PRODUCER_H_
#define PRODUCER_H_

#include "../Packets/PubPkt.h"
#include "../Packets/BackSubPkt.h"
#include "../Packets/RulePkt.h"
#include "../Packets/RulePktValueReference.h"
#include "../Common/Consts.h"
#include <stdio.h>
#include <sstream>

#include <boost/unordered_map.hpp>

#include <set>
#include "../Packets/PubPkt.h"
#include "../Common/Consts.h"
#include "ParamHandler.h"
#include "RandomGenerator.h"

#include <boost/math/distributions/normal.hpp>

/**
 * This class is used to produce publication packets, i.e. to simulate the load for
 * the system according to a set of given parameters.
 */
class Producer {

public:

	typedef struct {
		char name[NAME_LEN];
		ValType type;
		RandomGenerator *generator;
	} FieldDescrType;

	typedef struct {
		RandomGenerator *windowGenerator;
		RandomGenerator *occurrenceGenerator;
	} SubDescrType;

	/**
	 * Constructor: generates a producer with parameters stored in the given ParamHandler
	 */
	Producer(ParamHandler *parParamHandler, bool complex);

	/**
	 * Destructor
	 */
	virtual ~Producer();
	/**
	 * Computes again the set of names
	 */
	void resetNames();

	/**
	 * Computes again the set of values for string attributes
	 */
	void resetStringValues();

	/**
	 * Creates a new publication packet
	 */
	PubPkt * createPubPkt();

	/**
	 * Creates a new subscriprion packet
	 */
	BackSubPkt * createBackSubPkt();

	BackSubPkt * createComplexBackSubPkt();

	/**
	 * Returns a random operator compatible with the type
	 */
	Op getRandomOp(ValType type);

	/**
	 * Fills the rules set with the number of new packets specified in the parameter handler
	 */
	void createRulePkts(set<RulePkt *> &rules);

	/**
	 * Adds the root predicate to the given pkt
	 */
	int addRootPredicate(RulePkt *pkt, int i);

	/**
	 * Adds a new predicate to the given pkt.
	 * If canSplit==true, the predicate can generate a new sequence inside the rule.
	 * Returns true if it has generated a new sequence.
	 */
	bool addPredicate(RulePkt *pkt, bool canSplit, int noType);

	/**
	 * Adds a parameter constraint to the given pkt
	 */
	void addParameter(RulePkt *pkt);

	/**
	 * Adds a negation to the given pkt
	 */
	void addNegation(RulePkt *pkt);

	/**
	 * Returns a random event type
	 */
	int getRandomEventType();

	/**
	 * Initializes the given set of constraints
	 */
	void initConstraints(Constraint *constraints, int constraintsNum);

	/**
	 * Returns a valid time window for a constraint
	 */
	TimeMs getWindow();

	/**
	 * Returns a valid CompKind for a predicate
	 */
	CompKind getCompKind();

	map<char*, int> nameIds;      // map names to name identifiers (numbers)

private:
	ParamHandler *paramHandler;		// Handler of parameters
	vector<char*> names;							// Set of all possible names
	vector<char*> stringValues;				// Set of all possible values for strings
	boost::unordered_map<int,std::vector<FieldDescrType*> > pubDescrMap;
	boost::unordered_map<int, SubDescrType*> subDescrMap;
	RandomGenerator *randomEventTypeGen;
	RandomGenerator *randomSubsTypeGen;


	boost::unordered_map<int,std::vector<FieldDescrType*> > complexPubDescrMap;
	boost::unordered_map<int, SubDescrType*> complexSubDescrMap;
	RandomGenerator *complexRandomSubsTypeGen;

	void computeNameSet();
	void computeStringValues();

};


namespace test {


	Attribute produceIntAttribute(std::string name, int value);

	Attribute produceFloatAttribute(std::string name, float value);

	Attribute produceBoolAttribute(std::string name, bool value);

	Attribute produceStringAttribute(std::string name, std::string value);

	Constraint produceIntConstraint(std::string name, Op op, int value);

	Constraint produceFloatConstraint(std::string name, Op op, float value);

	Constraint produceBoolConstraint(std::string name, Op op, bool value);

	Constraint produceStringConstraint(std::string name, Op op, std::string value);

	std::string toString(PubPkt* pkt);

	std::string toString(BackSubPkt* pkt);

	std::string toString(RulePkt* pkt);

	std::string toString(const Attribute& attr);

	std::string toString(const Constraint& constr);

	std::string toString(OccurrenceType occurrence);

}


#endif /* PRODUCER_H_ */
